package com.hengpeng.common.monitor;

/**
 * <pre>
 * Title: 		LoadStatus.java
 * Project: 	MSBASE
 * Author:		linriqing
 * Create:	 	2012-12-21 下午03:19:24
 * Copyright: 	Copyright (c) 2012
 * Company:		Shenzhen Helper
 * <pre>
 */
import java.io.File;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.MemoryMXBean;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectInstance;
import javax.management.ObjectName;

import sun.management.ManagementFactory;

import com.hengpeng.common.monitor.dto.ServerStatus;
import com.hengpeng.common.monitor.dto.VmStatus;
import com.hengpeng.common.monitor.dto.ServerStatus.DiskStatus;
import com.hengpeng.common.monitor.dto.VmStatus.GcStatus;
import com.hengpeng.common.monitor.dto.VmStatus.MemoryUsage;
import com.hengpeng.common.monitor.dto.VmStatus.ThreadStatus;
import com.hengpeng.common.util.ObjectHelper;
import com.sun.management.OperatingSystemMXBean;

/**
 * <pre>
 * TODO 输入类型说明
 * </pre>
 * @author linriqing
 * @version 1.0, 2012-12-21
 */
public class LoadStatus
{
	private static final int MB = 1024 * 1024;

	private static final int CPUTIME = 30;

	private static final int PERCENT = 100;

	private static final int FAULTLENGTH = 10;

	public static ServerStatus loadServerStatus()
	{
		ServerStatus status = new ServerStatus();
		String hostIPLocal = "";
		String hostNameLocal = "";
		try
		{
			hostNameLocal = java.net.InetAddress.getLocalHost().getHostName();
			hostIPLocal = java.net.InetAddress.getLocalHost().getHostAddress();
			File[] roots = File.listRoots();// 获取磁盘分区列表
			for (File file : roots)
			{
				DiskStatus disk = new DiskStatus(file.getPath(), file.getUsableSpace() / MB, file.getTotalSpace() / MB);
				status.getDiskStatus().add(disk);
			}
		}
		catch (UnknownHostException e)
		{
			e.printStackTrace();
		}
		finally
		{
			status.setHostIP(hostIPLocal);
			status.setHostName(hostNameLocal);
		}

		OperatingSystemMXBean osmb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
		status.setTotalSwapSpace(osmb.getTotalSwapSpaceSize() / MB);
		status.setTotalMemory(osmb.getTotalPhysicalMemorySize() / MB);
		status.setOsArch(osmb.getArch());
		status.setOsVersion(osmb.getVersion());
		status.setProcessorCount(osmb.getAvailableProcessors());
		status.setOsName(osmb.getName());
		status.setFreeMemory(osmb.getFreePhysicalMemorySize() / MB);
		status.setLoadAverage(osmb.getSystemLoadAverage());
		status.setVirtualMemory(osmb.getCommittedVirtualMemorySize() / MB);
		status.setFreeSwapSpace(osmb.getFreeSwapSpaceSize() / MB);

		if (status.getOsName().toLowerCase().startsWith("windows"))
		{
			status.setLoadAverage(getCpuRatioForWindows() / PERCENT);
		}
		return status;
	}

	/** 获得CPU使用率. */
	private static double getCpuRatioForWindows()
	{
		try
		{
			String procCmd = System.getenv("windir") + "\\system32\\wbem\\wmic.exe process get Caption,CommandLine,"
					+ "KernelModeTime,ReadOperationCount,ThreadCount,UserModeTime,WriteOperationCount";
			// 取进程信息
			long[] c0 = readCpu(Runtime.getRuntime().exec(procCmd));
			Thread.sleep(CPUTIME);
			long[] c1 = readCpu(Runtime.getRuntime().exec(procCmd));
			if (c0 != null && c1 != null)
			{
				long idletime = c1[0] - c0[0];
				long busytime = c1[1] - c0[1];
				return Double.valueOf(PERCENT * (busytime) / (busytime + idletime)).doubleValue();
			}
			else
			{
				return 0.0;
			}
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
			return 0.0;
		}
	}

	private static long[] readCpu(final Process proc)
	{
		long[] retn = new long[2];
		try
		{
			proc.getOutputStream().close();
			InputStreamReader ir = new InputStreamReader(proc.getInputStream());
			LineNumberReader input = new LineNumberReader(ir);
			String line = input.readLine();
			if (line == null || line.length() < FAULTLENGTH)
			{
				return null;
			}
			int capidx = line.indexOf("Caption");
			int cmdidx = line.indexOf("CommandLine");
			int rocidx = line.indexOf("ReadOperationCount");
			int umtidx = line.indexOf("UserModeTime");
			int kmtidx = line.indexOf("KernelModeTime");
			int wocidx = line.indexOf("WriteOperationCount");
			long idletime = 0;
			long kneltime = 0;
			long usertime = 0;
			while ((line = input.readLine()) != null)
			{
				if (line.length() < wocidx)
				{
					continue;
				}
				// 字段出现顺序：Caption,CommandLine,KernelModeTime,ReadOperationCount,
				// ThreadCount,UserModeTime,WriteOperation
				String caption = line.substring(capidx, cmdidx - 1).trim();
				String cmd = line.substring(cmdidx, kmtidx - 1).trim();
				if (cmd.indexOf("wmic.exe") >= 0)
				{
					continue;
				}
				// log.info("line="+line);
				if (caption.equals("System Idle Process") || caption.equals("System"))
				{
					idletime += Long.valueOf(line.substring(kmtidx, rocidx - 1).trim()).longValue();
					idletime += Long.valueOf(line.substring(umtidx, wocidx - 1).trim()).longValue();
					continue;
				}

				kneltime += Long.valueOf(line.substring(kmtidx, rocidx - 1).trim()).longValue();
				usertime += Long.valueOf(line.substring(umtidx, wocidx - 1).trim()).longValue();

			}
			retn[0] = idletime;
			retn[1] = kneltime + usertime;
			return retn;
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		finally
		{
			try
			{
				proc.getInputStream().close();
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}
		return null;
	}

	public static VmStatus loadVmStatus()
	{
		VmStatus status = new VmStatus();
		status.setTotalMemory(Runtime.getRuntime().totalMemory() / MB);
		status.setMaxMemory(Runtime.getRuntime().maxMemory() / MB);
		status.setFreeMemory(Runtime.getRuntime().freeMemory() / MB);

		ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
		long[] allThreadIds = threadMXBean.getAllThreadIds();
		for (long l : allThreadIds)
		{
			ThreadInfo threadInfo = threadMXBean.getThreadInfo(l);
			status.getThreadStatus().add(new ThreadStatus(threadInfo.getThreadName(), threadInfo.getThreadState()));
		}

		List<GarbageCollectorMXBean> garbageCollectorMXBeans = ManagementFactory.getGarbageCollectorMXBeans();
		for (GarbageCollectorMXBean garbageCollectorMXBean : garbageCollectorMXBeans)
		{
			status.getGcStatus().add(
					new GcStatus(garbageCollectorMXBean.getName(), garbageCollectorMXBean.getCollectionTime(),
							garbageCollectorMXBean.getCollectionCount()));
		}

		MBeanServer server = java.lang.management.ManagementFactory.getPlatformMBeanServer();
		Set<ObjectInstance> set;
		try
		{
			set = server.queryMBeans(new ObjectName("*:type=RequestProcessor,*"), null);
			for (ObjectInstance object : set)
			{
				System.out.println(object.getObjectName() + ":" + object.getClassName());
			}
		}
		catch (MalformedObjectNameException e)
		{
			e.printStackTrace();
		}
		catch (NullPointerException e)
		{
			e.printStackTrace();
		}
		MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
		java.lang.management.MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage();
		MemoryUsage heapMemory = new MemoryUsage(heapMemoryUsage.getInit() / MB, heapMemoryUsage.getUsed() / MB,
				heapMemoryUsage.getCommitted() / MB, heapMemoryUsage.getMax() / MB);
		java.lang.management.MemoryUsage nonHeapMemoryUsage = memoryMXBean.getHeapMemoryUsage();
		MemoryUsage nonHeapMemory = new MemoryUsage(nonHeapMemoryUsage.getInit() / MB, nonHeapMemoryUsage.getUsed()
				/ MB, nonHeapMemoryUsage.getCommitted() / MB, nonHeapMemoryUsage.getMax() / MB);
		status.setHeapMemory(heapMemory);
		status.setNonHeapMemory(nonHeapMemory);

		RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
		status.setUpTime(runtimeMXBean.getUptime());
		status.setStartTime(new Date(runtimeMXBean.getStartTime()));
		status.setName(runtimeMXBean.getVmName());
		status.setBootParameters(Arrays.toString(runtimeMXBean.getInputArguments().toArray()));
		status.setVendor(runtimeMXBean.getVmVendor());
		status.setVersion(runtimeMXBean.getVmVersion());
		return status;
	}

	public static void main(String[] args)
	{
		ServerStatus loadServerStatus = LoadStatus.loadServerStatus();
		System.out.println(ObjectHelper.toJson(loadServerStatus));
		VmStatus vmStatus = LoadStatus.loadVmStatus();
		System.out.println(ObjectHelper.toJson(vmStatus));
	}
}
